package com.sunday.common.core.lambda.toolkit.support;


import java.io.*;

/**
 * 当前类是 {@link java.lang.invoke.SerializedLambda } 的一个镜像
 * <p>
 * 这个类似乎是创建了一个与java.lang.invoke.SerializedLambda相似的类，且可以用于将一个序列化的lambda函数转换为这个自定义的SerializedLambda类。
 * 重写SerializedLambda可能有几个理由：
 * <p>
 * 更好的控制：在有的场景下，你可能想要对lambda的序列化和反序列化过程有更多的控制。
 * 例如，你可能想要自定义序列化和反序列化的方式，或者对序列化和反序列化后的对象进行额外的处理。
 * 修复或避免问题：有可能是为了绕过一些JDK在序列化/反序列化lambda时的问题或限制。
 * 更好的API：有的时候，对外提供自定义接口可能会更符合需求。你可以根据应用程序的特性和需求，提供更方便，更易于理解和使用的API。
 * 在你给出的代码中，看起来extract方法重写了resolveClass函数，这样在反序列化对象的时候，当获取到JDK原生的SerializedLambda类时，
 * 它会返回这个自定义的SerializedLambda类，而不是JDK的SerializedLambda类。这使得开发人员可以使用自定义的SerializedLambda类获取更多的lambda函数的信息，
 * 或者进行更多的自定义操作。
 *
 * @author zsy
 * @since 2022/10/13
 */
public class SerializedLambda implements Serializable {

    private static final long serialVersionUID = 8025925345765570181L;

    private Class<?> capturingClass;
    private String functionalInterfaceClass;
    private String functionalInterfaceMethodName;
    private String functionalInterfaceMethodSignature;
    private String implClass;
    private String implMethodName;
    private String implMethodSignature;
    private int implMethodKind;
    private String instantiatedMethodType;
    private Object[] capturedArgs;

    /**
     * 通过反序列化转换 lambda 表达式，该方法只能序列化 lambda 表达式，不能序列化接口实现或者正常非 lambda 写法的对象
     *
     * @param serializable
     * @return {@link com.sunday.common.core.lambda.toolkit.support.SerializedLambda}
     */
    public static SerializedLambda extract(Serializable serializable) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(serializable);
            oos.flush();
            try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
                /**
                 * java.io.ObjectInputStream.resolveClass(ObjectStreamClass desc) 方法加载本地类相当于指定的流类的描述。子类可以实现此方法，允许类从备用源获取。
                 */
                @Override
                protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                    Class<?> clazz = super.resolveClass(desc);
                    // 如果获取的是 jdk原生的 SerializedLambda 修改为 镜像类
                    return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
                }
            }) {
                return (SerializedLambda) ois.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("This is impossible to happen", e);
        }
    }

    public String getImplMethodName() {
        return implMethodName;
    }

    public String getInstantiatedMethodType() {
        return instantiatedMethodType;
    }

    @Override
    public String toString() {
        return functionalInterfaceClass.substring(functionalInterfaceClass.lastIndexOf('/') + 1) + " -> " + implClass.substring(implClass.lastIndexOf('/') + 1) + "::" + implMethodName;
    }

}
